#include"texWriter.h"
/*//GLOBAL for dump beging to avoid extra brackets
int GL_BEGIN1 = 0,
    GL_BEGIN2 = 0;
*/
int dumpTex(FILE*f, node_t* root)
{
    assert(f);
    assert(root);
    fprintf(f, "\\documentclass{article}\n\\begin{document}\n$");
    printTex(f, root);
    fprintf(f, "$\n\\end{document}");
    return 0;
}

int dumpPreambule(FILE* f)
{
    assert(f);

    fprintf(f, "\\documentclass{article}\n\\begin{document}\n");
    fprintf(f,"\\begin{center}\nEasy defferentiate with Vladislav.\\end{center}\n\n");
    return 0;
}
int dumpEndOfDoc(FILE* f)
{
    assert(f);

    fprintf(f, "\n\\end{document}");
}

int dumpFormula(FILE* f, node_t* n)
{
    assert(f);
    assert(n);

    //GL_BEGIN1 = 0;
    //GL_BEGIN2 = 0;
    fprintf(f, "\n\n$");
    printTex(f, n);
    fprintf(f, "$\n");
}
int printTex(FILE* f, node_t* n)
{
    int printBracketsCirc = 0,
        printBracketsFig  = 0;
    printBracketsFig  = shouldPrintFig(n);
    printBracketsCirc = shouldPrintCirc(n);

    if(n->nType == DIV)
    {
        fprintf(f, "\\frac{");
        if (n->l) printTex(f, n->l);
        fprintf(f,"}{");
        if (n->r) printTex(f, n->r);
        fprintf(f, "}");
        return 0;
    }
    if (n->nType == PLUS)
    {
        if(n->l->nType == OPERATOR && n->l->l == NULL && n->l->r == NULL)
            {printTex(f,n->r); return 0;}
        else if(n->r->nType == OPERATOR && n->r->l == NULL && n->r->r == NULL)
            {printTex(f,n->l);return 0;}
    }
    if(printBracketsCirc) fprintf(f,"(");

    if(n->l) printTex(f, n->l);
    printData(f, n);
    if(n->r) printTex(f, n->r);

    if (printBracketsFig)  fprintf(f, "}");
    if (printBracketsCirc) fprintf(f, ")");
}

int printData(FILE* f, node_t* n)
{
    switch(n->nType)
    {
        case VARIABLE:
            fprintf(f, "%s", n->name);
            break;
        case NUMBER:
            fprintf(f, "%lg", n->value);
            break;
        case PLUS:
            fprintf(f, "+");
            break;
        case SUB:
            fprintf(f, "-");
            break;
        case MUL:
            fprintf(f, "*");
            break;
        case DIV:
            fprintf(f, "/");
            break;
        case MOV:
            fprintf(f, "=");
            break;
        case DEGREE:
            fprintf(f, "^{");
            break;
        case EXP:
            fprintf(f, "e^{");
            break;
        case LOG:
            fprintf(f, "\log{");
            break;
        case SIN:
            fprintf(f, "sin{");
            break;
        case COS:
            fprintf(f, "cos{");
            break;
        default:
            return 1;
    }
    return 0;
}

int shouldPrintCirc(node_t* n)
{
    if (n == NULL)
        return 0;
    if(n->nType == NUMBER && n->value >= 0 || n->nType == VARIABLE || n->nType == MUL || n->nType == DEGREE)
        return 0;
    if(n->nType == OPERATOR || n->nType == MOV)
        return 0;
    if((n->nType == PLUS || n->nType == SUB) &&
    (n->l->nType == PLUS || n->l->nType == SUB || n->r->nType == PLUS || n->r->nType == SUB))
        return 0;
    return 1;
}

int shouldPrintFig(node_t* n)
{
    if(n->nType == LOG || n->nType == DEGREE || n->nType == COS ||
    n->nType == SIN || n->nType == EXP)
        return 1;
    return 0;
}

int makeStrings(char** Strings,   char* buffer, int length)
{
    int n = 1;
    Strings[0] = buffer;
    for(int i = 1; i < length; i++)
        if(buffer[i] == '\n')
        {
            Strings[n] = buffer + i + 1;
            buffer[i] = 0;
            n++;
        }

    return n;
}

char** bufferize(FILE* f, int* n)
{
    if (f == NULL)
    {
        printf("\n ERROR: Null pointer in bufferize(FILE*)");
        abort();
    }
    int flen = fileLength(f);

    char* buffer = (char*) calloc(flen + 1, sizeof(char));
    *(buffer + flen) = 0;

    fread(buffer, flen, sizeof(char), f);
    fclose(f);

    int lineCount = CountOf(buffer, flen, '\n') + 1;
    printf("%d\n", lineCount);
    char** Strings = (char**) calloc(lineCount, sizeof(char*));

    *n = makeStrings(Strings, buffer, flen);
    return Strings;
}

int fileLength(FILE* f)
{
    if(f == NULL) return 0;

    int currentPos = ftell(f);

    int length = 0;
    int n = 0;
    fseek(f, 0, SEEK_SET);
    while(n != EOF){
        n = fgetc(f);
        length++;
    }
    fseek(f, currentPos, SEEK_SET);
    return length;
}

int CountOf(const   char *str, int length,   char ch)
{
    int counter = 0;
    for (int i = 0; i < length; i++)
        if (str[i] == ch) counter++;
    return counter;
}
